﻿<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>ComObjQuery()</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="../css/default.css" rel="stylesheet" type="text/css">
</head>
<body>

<h1>ComObjQuery() <span class="ver">[v1.0.96.00+]</span></h1>
<p>查询接口或服务的 COM 对象.</p>
<pre class="Syntax">InterfacePointer := ComObjQuery(ComObject, [SID,] IID)</pre>

<h3>参数</h3>
<table class="info">
  <tr>
    <td>ComObject</td>
    <td>COM 包装器对象或原始接口指针.</td>
  </tr>
  <tr>
    <td>IID</td>
    <td>格式为 &quot;{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}&quot; 的接口标识符 (GUID).</td>
  </tr>
  <tr>
    <td>SID</td>
    <td>与 IID 格式相同的服务标识符.此参数忽略时, 必须同时忽略后面的逗号.</td>
  </tr>
</table>

<h3>一般说明</h3>
<p>此函数的第一种形式相当于 <a href="http://msdn.microsoft.com/en-us/library/ms682521.aspx">IUnknown::QueryInterface</a>.第二种形式内部查询 <a href="http://msdn.microsoft.com/en-us/library/cc678965.aspx">IServiceProvider</a> 接口, 然后调用 <a href="http://msdn.microsoft.com/en-us/library/cc678966.aspx">IServiceProvider::QueryService</a>.在两种形式中, 返回值为零或到被请求接口的指针.通常当脚本结束时必须 <a href="ObjAddRef.htm">释放</a> 这种指针.</p>

<h3>相关</h3>
<a href="ObjAddRef.htm">ObjRelease</a>, <a href="ComObjCreate.htm">ComObjCreate</a>, <a href="ComObjGet.htm">ComObjGet</a>, <a href="ComObjActive.htm">ComObjActive</a>, <a href="ComObjError.htm">ComObjError</a>

<h3>示例</h3>

<pre id="ExClassName" class="NoIndent"><em>; 示例:确定一个对象的类名.</em>

obj := ComObjCreate("Scripting.Dictionary")

MsgBox % "Interface name: " ComObjType(obj, "name")

IID_IProvideClassInfo := "{B196B283-BAB4-101A-B69C-00AA00341D07}"

<em>; 请求到对象 IProvideClassInfo 接口的指针.</em>
if !(pci := ComObjQuery(obj, IID_IProvideClassInfo))
{
    MsgBox IProvideClassInfo interface not supported.
    return
}

<em>; 调用 GetClassInfo 以获取到 ITypeInfo 接口的指针.</em>
DllCall(vtable(pci, 3), "ptr", pci, "ptr*", ti)

<em>; 调用 GetDocumentation 以获取对象的完整类型名称.</em>
DllCall(vtable(ti, 12), "ptr", ti, "int", -1, "ptr*", name, "ptr", 0, "ptr", 0, "ptr", 0)

<em>; 转换 BSTR 指针为可用的字符串.</em>
name := StrGet(name, "UTF-16")

<em>; 释放原始接口指针.</em>
ObjRelease(ti)
ObjRelease(pci)

<em>; 显示类型名称!</em>
MsgBox % "Class name: " name

vtable(ptr, n) {
    <em>; NumGet(ptr+0) 返回对象的虚拟函数
    ; 表 (vtable for short) 的地址.表达式的其余部分从 vtable
    ; 获取第 n 个函数的地址.</em>
    return NumGet(NumGet(ptr+0), n*A_PtrSize)
}
</pre>

<pre id="ExIE" class="NoIndent"><em>; 示例:自动化现有的 Internet Explorer 窗口.</em>

sURL := "http://www.autohotkey.com/forum/"
if webBrowser := GetWebBrowser()
   webBrowser.Navigate(sURL)
return

GetWebBrowser()
{
    <em>; 获取到顶级 IE 窗口文档对象的原始指针.</em>
    static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
    SendMessage msg, 0, 0, Internet Explorer_Server1, ahk_class IEFrame
    if ErrorLevel = FAIL
        return  ; IE not found.
    lResult := ErrorLevel
    DllCall("oleacc\ObjectFromLresult", "ptr", lResult
        , "ptr", GUID(IID_IHTMLDocument2,"{332C4425-26CB-11D0-B483-00C04FD90119}")
        , "ptr", 0, "ptr*", pdoc)
    
    <em>; 查询 WebBrowserApp 服务.在这种特殊情况中,
    ; SID 和 IID 相同, 但不总是如此.</em>
    static IID_IWebBrowserApp := "{0002DF05-0000-0000-C000-000000000046}"
    static SID_SWebBrowserApp := IID_IWebBrowserApp
    pweb := ComObjQuery(pdoc, SID_SWebBrowserApp, IID_IWebBrowserApp)
    
    <em>; 释放文档对象指针.</em>
    ObjRelease(pdoc)
    
    <em>; 返回包装过的可用 WebBrowser 对象:</em>
    static VT_DISPATCH := 9, F_OWNVALUE := 1
    return ComObject(VT_DISPATCH, pweb, F_OWNVALUE)
}

GUID(ByRef GUID, sGUID) <em>; 转换一个字符串为二进制的 GUID 并返回其地址.</em>
{
    VarSetCapacity(GUID, 16, 0)
    return DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &amp;GUID) >= 0 ? &amp;GUID : ""
}
</pre>

</body>
</html>
